#include "StdAfx.h"
#include "BSplinePatchPathGenerator.h"
#include "Point3D.h"
#include "InitMachine.h"
#include "MilimetersMetricMeasure.h"
#include "PrismaticToolSpeed.h"
#include "RevoluteToolSpeed.h"
#include "SlowMotion.h"
#include "QuickMotion.h"
#include "ProgramEnd.h"
#include "ZigZagLineGenerator.h"
#include <memory.h>
#include <algorithm>
#include <exception>
#include <fstream>
using namespace std;

BSplinePatchPathGenerator::BSplinePatchPathGenerator(MillingMachine3C * machine,int samplesPerMaterialX,int samplesPerMaterialY,Point3D & pathMiddle)
{
	this->width = machine->width;
	this->height = machine->height;
	this->depth = machine->initDepth;
	this->pathMiddle = pathMiddle;
	this->samplesPerMaterialX = samplesPerMaterialX;
	this->samplesPerMaterialY = samplesPerMaterialY;
	this->material = new MaterialType();
	this->pathLineSweepGenerator = dynamic_cast<PathLineGenerator*>(new ZigZagLineGenerator(machine));
}

BSplinePatchPathGenerator::~BSplinePatchPathGenerator(void)
{
	delete this->pathLineSweepGenerator;
	for_each(this->material->begin(),this->material->end(),[](pair<MY_DATATYPE,MapType*>  pair){
		delete pair.second;
	});
	delete this->material;
}

void BSplinePatchPathGenerator::GeneratePath(BSplineSurface * surface, MillingTool * tool)
{
	for(float u=0.0;u<=surface->getUMaxGenerationValue();u+=0.02f)
	{
		for(float v=0.0;v<=surface->getVMaxGenerationValue();v+=0.02f)
		{
			Point3D ps = surface->getPointAt(u,v);
			MaterialType::iterator it;
			it = this->material->find(ps.y);
			//nie znaleziono y
			if(it==this->material->end())
			{
				MapType * nElem = new MapType();
				nElem->insert(make_pair(ps.x,ps));
				this->material->insert(make_pair(ps.y,nElem));
			}
			else
			{
				MapType::iterator it2;
				it2 = it->second->find(ps.x);
				if(it2==it->second->end())
					it->second->insert(make_pair(ps.x,ps));
				else
				{
					if(it2->second.z<ps.z)
					{
						it2->second.y = ps.y;
						it2->second.z = ps.z;
					}
				}
			}
		}
	}
}

void BSplinePatchPathGenerator::saveToFile(const char * fileName)
{
	try
	{
		ofstream o(fileName);
		for_each(this->states->begin(),this->states->end(),[&o](ConfigurationState * state)
		{
			state->serialize(o);
		});
		o.close();
	}
	catch(exception & e)
	{
	}
}

void BSplinePatchPathGenerator::generateConfigurationStates()
{
	int instructionNumber = 1;
	this->states = new vector<ConfigurationState*>();
	this->states->push_back(dynamic_cast<ConfigurationState*>(new MilimetersMetricMeasure(0)));
	this->states->push_back(dynamic_cast<ConfigurationState*>(new InitMachine(instructionNumber++)));
	this->states->push_back(dynamic_cast<ConfigurationState*>(new RevoluteToolSpeed(instructionNumber++,1000)));
	this->states->push_back(dynamic_cast<ConfigurationState*>(new PrismaticToolSpeed(instructionNumber++,15000)));

	MaterialType::iterator outerIt;
	for(outerIt = this->material->begin(); outerIt !=this->material->end();++outerIt)
	{
		MapType * map = outerIt->second;
		this->pathLineSweepGenerator->process(map,this->states,this->pathMiddle,instructionNumber);
	}

	double x = pathMiddle.x;
	double y = pathMiddle.y;

	this->states->push_back(dynamic_cast<ConfigurationState*>(new QuickMotion(instructionNumber++,(MY_DATATYPE)x,(MY_DATATYPE)y,300)));
	this->states->push_back(dynamic_cast<ConfigurationState*>(new ProgramEnd(instructionNumber++)));
}

int BSplinePatchPathGenerator::getHashIndex(Point3D & point)
{
	int code = point.getHashCode3D();
	return code < 0 ? code*(-17):code;
}